#include "scope.h"
#include "i2c.h"
#include "scope_core1.h"
#include "scope_output.h"

enum {
    SCOPE_output_TYPE_LOW,
    SCOPE_output_TYPE_HIGH,
    SCOPE_output_TYPE_SINE,
    SCOPE_output_TYPE_SQUARE,
    SCOPE_output_TYPE_TRIANGLE,
    SCOPE_output_TYPE_SAWTOOTH,
    SCOPE_output_TYPE_NOISE,
} scope_output_type_t;

static int g_scope_output_type = 2;
static int g_scope_output_freq = 2;
static int g_scope_output_amp = 3300;
static int g_scope_output_value_last = 0;

static void scope_output_low(void)
{
    mcp4725_output_set_mv(0);
    scope_core1_stop();
}

static void scope_output_high(void)
{
    mcp4725_output_set_mv(g_scope_output_amp);
    scope_core1_stop();
}

static void scope_output_sine(void)
{
    int value = 0;
    //time_us_32()
    while (1) {
        value = g_scope_output_amp / 2.0 * sin(2.0 * M_PI * g_scope_output_freq * time_us_32() / 1000000) + g_scope_output_amp / 2.0;
        if (value != g_scope_output_value_last) {
            g_scope_output_value_last = value;
            mcp4725_output_set_mv(value); 
        }
        scope_core1_poll();
    }
}

static void scope_output_square(void)
{
    while (1) {
        mcp4725_output_set_mv(0);
        busy_wait_us_32(1000000 / g_scope_output_freq / 2);
        mcp4725_output_set_mv(g_scope_output_amp);
        busy_wait_us_32(1000000 / g_scope_output_freq / 2);
        scope_core1_poll();
    }
}

static void scope_output_triangle(void)
{
    int value = 0;

    while (1) {
        value = (g_scope_output_amp / 1000000.0) * ((time_us_32() * g_scope_output_freq) % 1000000);
        if (value != g_scope_output_value_last) {
            g_scope_output_value_last = value;
            mcp4725_output_set_mv(value); 
        }
        scope_core1_poll();
    }
}

static void scope_output_sawtooth(void)
{
    uint32_t current_time;
    uint32_t period_us;          // 周期，单位微秒
    uint32_t half_period_us;     // 半周期，单位微秒
    uint32_t time_in_period;     // 当前时间在周期中的位置
    int current_dac = -1;        // 当前DAC值，初始化为无效值
    int new_dac;                 // 计算得到的新DAC值
    
    while (1) {
        period_us = 1000000 / g_scope_output_freq;
        half_period_us = period_us / 2; 
        
        // 计算当前在周期中的位置(0到period_us-1)
        time_in_period = time_us_32() % period_us;
        
        // 计算三角波当前值
        if (time_in_period < half_period_us) {
            // 上升沿：从0线性增加到最大值
            // 使用整数运算避免浮点计算
            new_dac = (int)(((uint64_t)time_in_period * g_scope_output_amp) / half_period_us);
        } else {
            // 下降沿：从最大值线性减少到0
            uint32_t time_in_second_half = time_in_period - half_period_us;
            new_dac = (int)(g_scope_output_amp - 
                          ((uint64_t)time_in_second_half * g_scope_output_amp) / half_period_us);
        }
        
        // 确保DAC值在有效范围内
        if (new_dac < 0) {
            new_dac = 0;
        } else if ((uint32_t)new_dac > g_scope_output_amp) {
            new_dac = g_scope_output_amp;
        }
        
        // 只有当DAC值变化时才输出
        if (new_dac != current_dac) {
            mcp4725_output_set_mv(new_dac);
            current_dac = new_dac;
        }
        scope_core1_poll();
    }
}


static void scope_output_noise(void)
{
    int value = 0;

    while (1) {    
        value = rand() % g_scope_output_amp;
        if (value != g_scope_output_value_last) {
            g_scope_output_value_last = value;
            mcp4725_output_set_mv(value); 
        }  
        scope_core1_poll();
    }
}

struct {
    char *name;
    void (*func)(void);
} g_score_output_info[] = {
    {"Low", scope_output_low},
    {"High", scope_output_high},
    {"Sin", scope_output_sine},
    {"Square", scope_output_square},
    {"Triangle", scope_output_triangle},
    {"Sawtooth", scope_output_sawtooth},
    {"Noise", scope_output_noise},
};

void scope_output_start(void)
{
    if (g_scope_output_type < sizeof(g_score_output_info) / sizeof(g_score_output_info[0])) {
        scope_core1_start(g_score_output_info[g_scope_output_type].func);
    }
}

static void scope_output_proc_type(char *value)
{   
    for (int i = 0; i < sizeof(g_score_output_info) / sizeof(g_score_output_info[0]); i++) {
        if (strcmp(g_score_output_info[i].name, value) == 0) {
            g_scope_output_type = i;
            break;
        }
    }
    scope_output_start();
    log_printf("OutputType: %d\n", g_scope_output_type);
}
HTTPD_CGI_PARAM_DEFINE("OutputType", scope_output_proc_type);

static void scope_output_proc_fre(char *value)
{
    g_scope_output_freq = atoi(value);
    if (g_scope_output_freq == 0) {
        g_scope_output_freq = 100;
    }
    scope_output_start();
    log_printf("OutputFreq: %d\n", g_scope_output_freq);
}
HTTPD_CGI_PARAM_DEFINE("OutputFreq", scope_output_proc_fre);

static void scope_output_proc_amp(char *value)
{
    g_scope_output_amp = atoi(value);
    if (g_scope_output_amp == 0) {
        g_scope_output_amp = 1000;
    }
    scope_output_start();
    log_printf("OutputAmp: %d\n", g_scope_output_amp);
}
HTTPD_CGI_PARAM_DEFINE("OutputAmp", scope_output_proc_amp);

static void output_setup(void) 
{
    scope_output_start();
}

static void output_loop(void) 
{ 
}

I2C_CLIENT_DEFINE(output_setup, output_loop);

static int scope_fs_open_output_json(struct fs_file *file, const char *name, void **priv)
{
    char buffer[400] = {0};
    int len = 0;

    len += snprintf(&buffer[len], sizeof(buffer) - len - 1, 
        "{\n"
        "\"SupportWaveType\":[\n"
    );
    for (int i = 0; i < sizeof(g_score_output_info) / sizeof(g_score_output_info[0]); i++) {
        len += snprintf(&buffer[len], sizeof(buffer) - len - 1, 
            "\"%s\"%s\n",
            g_score_output_info[i].name,
            i == sizeof(g_score_output_info) / sizeof(g_score_output_info[0]) - 1 ? "]," : ","
        );
    }
    len += snprintf(&buffer[len], sizeof(buffer) - len - 1, 
        "\"OutputType\":\"%s\",\n",
        g_score_output_info[g_scope_output_type].name
    );
    len += snprintf(&buffer[len], sizeof(buffer) - len - 1, 
        "\"OutputFreq\":%d,\n",
        g_scope_output_freq
    );
    len += snprintf(&buffer[len], sizeof(buffer) - len - 1, 
        "\"OutputAmp\":%d\n}",
        g_scope_output_amp
    );

    file->len = len;
    file->index = file->len;
    file->data = malloc(file->len + 1);
    file->flags = 0;
    memcpy((char *)file->data, buffer, file->len);
    return 1;
}

HTTPD_FILE_DEFINE("/output.json", scope_fs_open_output_json, NULL, NULL, NULL);
